import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:mime/mime.dart';

import 'abs_http_ui_handler.dart';
import 'http_data.dart';
import 'package:path/path.dart' as path;

/// 请求工具封装
class HttpUtils {
  static late ValueGetter<Dio> getDio;
  static late String Function({String? path}) createUrl;
  static late M? Function<M>(dynamic json) fromJsonAsT;
  static late Function(HttpResponse data, {AbsHttpUiHandler? handle}) handleResult;

  static Options checkOptions(String method, Options? options) {
    options ??= Options();
    options.method ??= method;
    return options;
  }

  /// 发送Get请求
  static Future<T> get<T>({
    T Function(Map<String, dynamic>)? parser,
    AbsHttpUiHandler? handler,
    String url = "",
    String? path,
    Map<String, dynamic>? queryParameters,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return request<T>(
      parser: parser,
      handler: handler,
      url: url,
      path: path,
      queryParameters: queryParameters,
      options: checkOptions('GET', options),
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  /// 发送Get请求
  static Future<T> post<T>({
    T Function(Map<String, dynamic>)? parser,
    AbsHttpUiHandler? handler,
    String url = "",
    String? path,
    Map<String, dynamic>? queryParameters,
    dynamic data,
    bool? isToFormData,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    return request<T>(
      parser: parser,
      handler: handler,
      url: url,
      path: path,
      queryParameters: queryParameters,
      data: data,
      isToFormData: isToFormData,
      options: checkOptions('POST', options),
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
  }

  /// 发送请求
  static Future<T> request<T>({
    T Function(Map<String, dynamic>)? parser,
    AbsHttpUiHandler? handler,
    String url = "",
    String? path,
    dynamic data,
    bool? isToFormData,
    Map<String, dynamic>? queryParameters,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    handler?.start();
    var result;
    Response res;
    try {
      res = await getDio().request(url.isEmpty ? createUrl(path: path) : url + (path ?? ""),
          options: checkOptions('POST', options),
          data: await handlerData(data, isToFormData),
          queryParameters: queryParameters,
          cancelToken: handler?.cancelToken,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress);
      //解析成mode
      // result = _parseData<T>(res.data);
      result = parser?.call(res.data) ?? fromJsonAsT<T>(json) as T;
      handleResult(result, handle: handler);
      // 将 success() 同步执行优先与外部
      handler?.success(result);
    } catch (e, stackTrace) {
      handler?.error(e, stackTrace);
      //这里只有抛出错误才能阻止调用者继续执行
      rethrow;
    } finally {
      // 将 completed() 推迟到微任务队列末尾
      if (handler != null) {
        Future.microtask(() {
          handler.completed();
        });
      }
    }
    //如果hander没有设置 直接返回结果
    return result;
  }

  /// 解析结果
  static T _parseData<T>(Map<String, dynamic> json) {
    // 使用 Type 对象进行类型检查，并假设每个类都有静态的 fromJson 方法。
    if (T == HttpResponse) {
      return HttpResponse().fromJson(json) as T;
    } else if (T.toString().startsWith("HttpResult")) {
      return HttpResult().fromJson(json) as T;
    }
    // else if (T.toString().startsWith("HttpPageResult")) {
    //   return HttpPageResult().fromJson(json) as T;
    // }
    else {
      // 如果无法识别的类型，尝试使用 JsonConvert 进行解析
      return fromJsonAsT<T>(json) as T;
    }
  }

  static Future<MultipartFile> createMultipartFile(String key, File file) async {
    // 自动获取文件名和 MIME 类型
    final filename = path.basename(file.path);
    final mimeType = lookupMimeType(file.path);
    return await MultipartFile.fromFile(
      file.path,
      filename: filename,
      contentType: mimeType != null ? DioMediaType.parse(mimeType) : DioMediaType('application', 'octet-stream'), // 默认类型
    );
  }

  static Future<Map<String, MultipartFile>> createMultipartFiles(String key, List<File> files) async {
    Map<String, MultipartFile> result = {};
    for (var i = 0; i < files.length; i++) {
      final keyX = "$key[$i]";
      result[keyX] = await createMultipartFile(keyX, files[i]);
    }
    return result;
  }

  //处理请求data
  //1:文件类型处理
  static Future<dynamic> handlerData(data, bool? isToFormData) async {
    var toData = data;
    if (data is Map<String, dynamic>) {
      Map<String, dynamic> result = {};
      //判断map 的value是否有文件类型
      bool havFile = false;
      for (var key in data.keys) {
        if (data[key] is File) {
          havFile = true;
          result[key] = await createMultipartFile(key, data[key]);
        } else if (data[key] is List<File>) {
          havFile = true;
          result.addAll(await createMultipartFiles(key, data[key]));
        } else {
          result[key] = data[key];
        }
      }
      if (havFile || isToFormData == true) {
        //重新构建成 FormData
        toData = FormData.fromMap(result);
      }
    }
    return toData;
  }
}
